{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Discover, Customize and Access NSIDC DAAC Data\n",
    "\n",
    "This notebook is based off of the [NSIDC-Data-Access-Notebook](https://github.com/nsidc/NSIDC-Data-Access-Notebook) provided through NSIDC's Github organization. \n",
    "\n",
    "Now that we've visualized our study areas, we will first explore data coverage, size, and customization (subsetting, reformatting, reprojection) service availability, and then access those associated files. The __Data access for all datasets__ notebook provides the steps needed to subset and download all the data we'll be using in the final __Visualize and Analyze Data__.\n",
    "\n",
    "___A note on data access options:___\n",
    "We will be pursuing data discovery and access \"programmatically\" using Application Programming Interfaces, or APIs. \n",
    "\n",
    "*What is an API?* You can think of an API as a middle man between an application or end-use (in this case, us) and a data provider. In this case the data provider is both the Common Metadata Repository (CMR) housing data information, and NSIDC as the data distributor. These APIs are generally structured as a URL with a base plus individual key-value-pairs separated by ‘&’.\n",
    "\n",
    "There are other discovery and access methods available from NSIDC including access from the data set landing page 'Download Data' tab (e.g. [ATL07 Data Access](https://nsidc.org/data/atl07?qt-data_set_tabs=1#qt-data_set_tabs)) and [NASA Earthdata Search](https://search.earthdata.nasa.gov/). Programmatic API access is beneficial for those of you who want to incorporate data access into your visualization and analysis workflow. This method is also reproducible and documented to ensure data provenance. \n",
    "\n",
    "Here are the steps you will learn in this customize and access notebook:\n",
    "   \n",
    "1. Search for data programmatically using the Common Metadata Repository API by time and area of interest.\n",
    "2. Determine subsetting, reformatting, and reprojection capabilities for our data of interest.\n",
    "3. Access and customize data using NSIDC's data access and service API."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Import packages\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import requests\n",
    "import getpass\n",
    "import json\n",
    "\n",
    "# This is our functions module. We created several functions used in this notebook and the Visualize and Analyze notebook.\n",
    "import tutorial_helper_functions as fn "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Explore data availability using the Common Metadata Repository \n",
    "\n",
    "The Common Metadata Repository (CMR) is a high-performance, high-quality, continuously evolving metadata system that catalogs Earth Science data and associated service metadata records. These metadata records are registered, modified, discovered, and accessed through programmatic interfaces leveraging standard protocols and APIs. Note that not all NSIDC data can be searched at the file level using CMR, particularly those outside of the NASA DAAC program. \n",
    "\n",
    "CMR API documentation: https://cmr.earthdata.nasa.gov/search/site/docs/search/api.html"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Select data set and determine version number\n",
    "\n",
    "Data sets are selected by data set IDs (e.g. ATL07). In the CMR API documentation, a data set ids is referred to as a \"short name\". These short names are located at the top of each NSIDC data set landing page in gray above the full title. We are using the Python Requests package to access the CMR. Data are then converted to [JSON](https://en.wikipedia.org/wiki/JSON) format; a language independant human-readable open-standard file format. More than one version can exist for a given data set: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "dataset_id: ATLAS/ICESat-2 L3A Sea Ice Height V001, version_id: 001\n",
      "dataset_id: ATLAS/ICESat-2 L3A Sea Ice Height V002, version_id: 002\n"
     ]
    }
   ],
   "source": [
    "CMR_COLLECTIONS_URL = 'https://cmr.earthdata.nasa.gov/search/collections.json' # CMR collection metadata endpoint\n",
    "response = requests.get(CMR_COLLECTIONS_URL, params={'short_name': 'ATL07'}) # Request metadata of specified short name\n",
    "\n",
    "results = json.loads(response.content) # load JSON results\n",
    "# for each version entry, print version number\n",
    "for entry in results['feed']['entry']:\n",
    "    fn.print_cmr_metadata(entry) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We will specify the most recent version for our remaining data set queries."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Select time and area of interest"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We will create a simple dictionary with our short name, version, time, and area of interest. We'll continue to add to this dictionary as we discover more information about our data set. The bounding box coordinates cover our region of interest over the East Siberian Sea and the temporal range covers March 23, 2019. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "bounding_box = '140,72,153,80' # Bounding Box spatial parameter in decimal degree 'W,S,E,N' format. \n",
    "temporal = '2019-03-23T00:00:00Z,2019-03-23T23:59:59Z' # Each date in yyyy-MM-ddTHH:mm:ssZ format; date range in start,end format"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Start our data dictionary with our data set, version, and area and time of interest. \n",
    "\n",
    "**Note that some version IDs include 3 digits and others include only 1 digit. Make sure to enter this value exactly as reported above.**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "data_dict = {'short_name': 'ATL07', \n",
    "             'version': '002',\n",
    "             'bounding_box': bounding_box, \n",
    "             'temporal': temporal }"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Determine how many files exist over this time and area of interest, as well as the average size and total volume of those granules\n",
    "\n",
    "We will use the `granule_info` function to query the CMR granule API. The function prints the number of granules, average size, and total volume of those granules. It returns the granule number value, which we will add to our data dictionary."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "There are 3 granules of ATL07 version 002 over my area and time of interest.\n",
      "The average size of each granule is 260.65 MB and the total size of all 3 granules is 781.94 MB\n"
     ]
    }
   ],
   "source": [
    "gran_num = fn.granule_info(data_dict)\n",
    "data_dict['gran_num'] = gran_num # add file number to data dictionary"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that subsetting, reformatting, or reprojecting can alter the size of the granules if those services are applied to your request."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ***On your own***: Discover data availability for ATL07\n",
    "\n",
    "Go back to the \"Select data set and determine version number\" heading. Replace all `MOD29` instances with `ATL07` along with its most recent version number, keeping your time and area of interest the same. ***Note that ATL07 has a 3-digit version number.*** How does the data volume compare to MOD29? \n",
    "\n",
    "____"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Determine the subsetting, reformatting, and reprojection services enabled for your data set of interest."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The NSIDC DAAC supports customization (subsetting, reformatting, reprojection) services on many of our NASA Earthdata mission collections. Let's discover whether or not our data set has these services available using the `print_service_options` function. If services are available, we will also determine the specific service options supported for this data set, which we will then add to our data dictionary. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Input Earthdata Login credentials\n",
    "\n",
    "An Earthdata Login account is required to query data services and to access data from the NSIDC DAAC. If you do not already have an Earthdata Login account, visit http://urs.earthdata.nasa.gov to register. We will input our credentials below, and we'll add our email address to our dictionary for use in our final access request."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdin",
     "output_type": "stream",
     "text": [
      "Earthdata Login password:  ·········\n"
     ]
    }
   ],
   "source": [
    "uid = '' # Enter Earthdata Login user name\n",
    "\n",
    "pswd = getpass.getpass('Earthdata Login password: ') # Input and store Earthdata Login password\n",
    "\n",
    "email = '' # Enter email associated with Earthata Login account\n",
    "\n",
    "data_dict['email'] = email # Add to data dictionary"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We now need to create an HTTP session in order to store cookies and pass our credentials to the data service URLs. The capability URL below is what we will query to determine service information. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Query service capability URL \n",
    "capability_url = f'https://n5eil02u.ecs.nsidc.org/egi/capabilities/{data_dict[\"short_name\"]}.{data_dict[\"version\"]}.xml' \n",
    "\n",
    "# Create session to store cookie and pass credentials to capabilities url\n",
    "session = requests.session() \n",
    "s = session.get(capability_url)\n",
    "response = session.get(s.url,auth=(uid,pswd))\n",
    "response.raise_for_status() # Raise bad request to check that Earthdata Login credentials were accepted "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This function provides a list of all available services:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Services available for ATL07 :\n",
      "\n",
      "Bounding box subsetting\n",
      "Shapefile subsetting\n",
      "Temporal subsetting\n",
      "Variable subsetting\n",
      "Reformatting to the following options: ['TABULAR_ASCII', 'NetCDF4-CF', 'NetCDF-3']\n"
     ]
    }
   ],
   "source": [
    "fn.print_service_options(data_dict, response)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Populate data dictionary with services of interest\n",
    "\n",
    "We already added our CMR search keywords to our data dictionary, so now we need to add the service options we want to request. A list of all available service keywords for use with NSIDC's access and service API are available in our [Key-Value-Pair table](https://nsidc.org/support/tool/table-key-value-pair-kvp-operands-subsetting-reformatting-and-reprojection-services), as a part of our [Programmatic access guide](https://nsidc.org/support/how/how-do-i-programmatically-request-data-services). For our ATL07 request, we are interested in bounding box, temporal, and variable subsetting. These options crop the data values to the specified ranges and variables of interest. We will enter those values into our data dictionary below.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "__Bounding box subsetting:__ Output files are cropped to the specified bounding box extent.\n",
    "\n",
    "__Temporal subsetting:__ Output files are cropped to the specified temporal range extent."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "data_dict['bbox'] = '140,72,153,80' # Just like with the CMR bounding box search parameter, this value is provided in decimal degree 'W,S,E,N' format. \n",
    "data_dict['time'] = '2019-03-23T00:00:00,2019-03-23T23:59:59' # Each date in yyyy-MM-ddTHH:mm:ss format; Date range in start,end format"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "__Variable subsetting:__ Subsets the data set variable or group of variables. For hierarchical data, all lower level variables are returned if a variable group or subgroup is specified. \n",
    "\n",
    "For ATL07, we will use only strong beams since these groups contain higher coverage and resolution due to higher surface returns. According to the user guide, the spacecraft was in the backwards orientation during our day of interest, setting the `gt*l` beams as the strong beams. \n",
    "\n",
    "We'll use these primary geolocation, height and quality variables of interest for each of the three strong beams. The following descriptions are provided in the [ATL07 Data Dictionary](https://nsidc.org/sites/nsidc.org/files/technical-references/ATL07-data-dictionary-v001.pdf), with additional information on the algorithm and variable descriptions in the [ATBD (Algorithm Theoretical Basis Document)](https://icesat-2.gsfc.nasa.gov/sites/default/files/page_files/ICESat2_ATL07_ATL10_ATBD_r002.pdf).\n",
    "\n",
    "`delta_time`: Number of GPS seconds since the ATLAS SDP epoch. \n",
    "\n",
    "`latitude`: Latitude, WGS84, North=+, Lat of segment center\n",
    "\n",
    "`longitude`: Longitude, WGS84, East=+,Lon of segment center\n",
    "\n",
    "`height_segment_height`: Mean height from along-track segment fit determined by the sea ice algorithm\n",
    "\n",
    "`height_segment_confidence`: Confidence level in the surface height estimate based on the number of photons; the background noise rate; and the error\n",
    "analysis\n",
    "\n",
    "`height_segment_quality`: Height segment quality flag, 1 is good quality, 0 is bad\n",
    "\n",
    "`height_segment_surface_error_est`: Error estimate of the surface height (reported in meters)\n",
    "\n",
    "`height_segment_length_seg`: along-track length of segment containing n_photons_actual"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "data_dict['coverage'] = '/gt1l/sea_ice_segments/delta_time,\\\n",
    "/gt1l/sea_ice_segments/latitude,\\\n",
    "/gt1l/sea_ice_segments/longitude,\\\n",
    "/gt1l/sea_ice_segments/heights/height_segment_confidence,\\\n",
    "/gt1l/sea_ice_segments/heights/height_segment_height,\\\n",
    "/gt1l/sea_ice_segments/heights/height_segment_quality,\\\n",
    "/gt1l/sea_ice_segments/heights/height_segment_surface_error_est,\\\n",
    "/gt1l/sea_ice_segments/heights/height_segment_length_seg,\\\n",
    "/gt2l/sea_ice_segments/delta_time,\\\n",
    "/gt2l/sea_ice_segments/latitude,\\\n",
    "/gt2l/sea_ice_segments/longitude,\\\n",
    "/gt2l/sea_ice_segments/heights/height_segment_confidence,\\\n",
    "/gt2l/sea_ice_segments/heights/height_segment_height,\\\n",
    "/gt2l/sea_ice_segments/heights/height_segment_quality,\\\n",
    "/gt2l/sea_ice_segments/heights/height_segment_surface_error_est,\\\n",
    "/gt2l/sea_ice_segments/heights/height_segment_length_seg,\\\n",
    "/gt3l/sea_ice_segments/delta_time,\\\n",
    "/gt3l/sea_ice_segments/latitude,\\\n",
    "/gt3l/sea_ice_segments/longitude,\\\n",
    "/gt3l/sea_ice_segments/heights/height_segment_confidence,\\\n",
    "/gt3l/sea_ice_segments/heights/height_segment_height,\\\n",
    "/gt3l/sea_ice_segments/heights/height_segment_quality,\\\n",
    "/gt3l/sea_ice_segments/heights/height_segment_surface_error_est,\\\n",
    "/gt3l/sea_ice_segments/heights/height_segment_length_seg'\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Select data access configurations\n",
    "\n",
    "The data request can be accessed asynchronously or synchronously. The asynchronous option will allow concurrent requests to be queued and processed as orders. Those requested orders will be delivered to the specified email address, or they can be accessed programmatically as shown below. Synchronous requests will automatically download the data as soon as processing is complete. For this tutorial, we will be selecting the asynchronous method. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "base_url = 'https://n5eil02u.ecs.nsidc.org/egi/request' # Set NSIDC data access base URL\n",
    "data_dict['request_mode'] = 'async' # Set the request mode to asynchronous\n",
    "data_dict['page_size'] = 2000 # Set the page size to the maximum of 2000, which equals the number of output files that can be returned"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Create the data request API endpoint \n",
    "Programmatic API requests are formatted as HTTPS URLs that contain key-value-pairs specifying the service operations that we specified above. We will first create a string of key-value-pairs from our data dictionary and we'll feed those into our API endpoint. This API endpoint can be executed via command line, a web browser, or in Python below. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "https://n5eil02u.ecs.nsidc.org/egi/request?short_name=ATL07&version=002&bounding_box=140,72,153,80&temporal=2019-03-23T00:00:00Z,2019-03-23T23:59:59Z&page_size=2000&email=amy.steiker@nsidc.org&bbox=140,72,153,80&time=2019-03-23T00:00:00,2019-03-23T23:59:59&coverage=/gt1l/sea_ice_segments/delta_time,/gt1l/sea_ice_segments/latitude,/gt1l/sea_ice_segments/longitude,/gt1l/sea_ice_segments/heights/height_segment_confidence,/gt1l/sea_ice_segments/heights/height_segment_height,/gt1l/sea_ice_segments/heights/height_segment_quality,/gt1l/sea_ice_segments/heights/height_segment_surface_error_est,/gt1l/sea_ice_segments/heights/height_segment_length_seg,/gt2l/sea_ice_segments/delta_time,/gt2l/sea_ice_segments/latitude,/gt2l/sea_ice_segments/longitude,/gt2l/sea_ice_segments/heights/height_segment_confidence,/gt2l/sea_ice_segments/heights/height_segment_height,/gt2l/sea_ice_segments/heights/height_segment_quality,/gt2l/sea_ice_segments/heights/height_segment_surface_error_est,/gt2l/sea_ice_segments/heights/height_segment_length_seg,/gt3l/sea_ice_segments/delta_time,/gt3l/sea_ice_segments/latitude,/gt3l/sea_ice_segments/longitude,/gt3l/sea_ice_segments/heights/height_segment_confidence,/gt3l/sea_ice_segments/heights/height_segment_height,/gt3l/sea_ice_segments/heights/height_segment_quality,/gt3l/sea_ice_segments/heights/height_segment_surface_error_est,/gt3l/sea_ice_segments/heights/height_segment_length_seg&request_mode=async\n"
     ]
    }
   ],
   "source": [
    "# Create a new param_dict with CMR configuration parameters removed from our data_dict \n",
    "param_dict = dict((i, data_dict[i]) for i in data_dict if i!='gran_num' and i!='page_num')\n",
    "\n",
    "param_string = '&'.join(\"{!s}={!r}\".format(k,v) for (k,v) in param_dict.items()) # Convert param_dict to string\n",
    "param_string = param_string.replace(\"'\",\"\") # Remove quotes\n",
    "\n",
    "API_request = f'{base_url}?{param_string}' \n",
    "print(API_request) # Print API base URL + request parameters"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Request data and clean up Output folder"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We will now download data using the `request_data` function, which utilizes the Python requests library. Our param_dict and HTTP session will be passed to the function to allow Earthdata Login access. The data will be downloaded directly to this notebook directory in a new Outputs folder. The progress of the order will be reported. The data are returned in separate files, so we'll use the `clean_folder` function to remove those individual folders."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Request HTTP response:  201\n",
      "\n",
      "Order request URL:  https://n5eil02u.ecs.nsidc.org/egi/request?short_name=ATL07&version=002&bounding_box=140%2C72%2C153%2C80&temporal=2019-03-23T00%3A00%3A00Z%2C2019-03-23T23%3A59%3A59Z&page_size=2000&email=amy.steiker%40nsidc.org&bbox=140%2C72%2C153%2C80&time=2019-03-23T00%3A00%3A00%2C2019-03-23T23%3A59%3A59&coverage=%2Fgt1l%2Fsea_ice_segments%2Fdelta_time%2C%2Fgt1l%2Fsea_ice_segments%2Flatitude%2C%2Fgt1l%2Fsea_ice_segments%2Flongitude%2C%2Fgt1l%2Fsea_ice_segments%2Fheights%2Fheight_segment_confidence%2C%2Fgt1l%2Fsea_ice_segments%2Fheights%2Fheight_segment_height%2C%2Fgt1l%2Fsea_ice_segments%2Fheights%2Fheight_segment_quality%2C%2Fgt1l%2Fsea_ice_segments%2Fheights%2Fheight_segment_surface_error_est%2C%2Fgt1l%2Fsea_ice_segments%2Fheights%2Fheight_segment_length_seg%2C%2Fgt2l%2Fsea_ice_segments%2Fdelta_time%2C%2Fgt2l%2Fsea_ice_segments%2Flatitude%2C%2Fgt2l%2Fsea_ice_segments%2Flongitude%2C%2Fgt2l%2Fsea_ice_segments%2Fheights%2Fheight_segment_confidence%2C%2Fgt2l%2Fsea_ice_segments%2Fheights%2Fheight_segment_height%2C%2Fgt2l%2Fsea_ice_segments%2Fheights%2Fheight_segment_quality%2C%2Fgt2l%2Fsea_ice_segments%2Fheights%2Fheight_segment_surface_error_est%2C%2Fgt2l%2Fsea_ice_segments%2Fheights%2Fheight_segment_length_seg%2C%2Fgt3l%2Fsea_ice_segments%2Fdelta_time%2C%2Fgt3l%2Fsea_ice_segments%2Flatitude%2C%2Fgt3l%2Fsea_ice_segments%2Flongitude%2C%2Fgt3l%2Fsea_ice_segments%2Fheights%2Fheight_segment_confidence%2C%2Fgt3l%2Fsea_ice_segments%2Fheights%2Fheight_segment_height%2C%2Fgt3l%2Fsea_ice_segments%2Fheights%2Fheight_segment_quality%2C%2Fgt3l%2Fsea_ice_segments%2Fheights%2Fheight_segment_surface_error_est%2C%2Fgt3l%2Fsea_ice_segments%2Fheights%2Fheight_segment_length_seg&request_mode=async\n",
      "\n",
      "order ID:  5000000435084\n",
      "status URL:  https://n5eil02u.ecs.nsidc.org/egi/request/5000000435084\n",
      "HTTP response from order response URL:  201\n",
      "\n",
      "Initial request status is  processing\n",
      "\n",
      "Status is not complete. Trying again.\n",
      "Retry request status is:  complete_with_errors\n",
      "Zip download URL:  https://n5eil02u.ecs.nsidc.org/esir/5000000435084.zip\n",
      "Beginning download of zipped output...\n",
      "Data request is complete.\n"
     ]
    }
   ],
   "source": [
    "fn.request_data(param_dict,session)\n",
    "fn.clean_folder()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To review, we have explored data availability and volume over a region and time of interest, discovered and selected data customization options, constructed API endpoints for our requests, and downloaded data. Let's move on to the analysis portion of the tutorial."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
